﻿using PipeDetection.Model;
using System;
using System.Collections.Generic;
using System.Drawing.Drawing2D;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Sunny.UI;

namespace PipeDetection.UI
{
    internal class Common
    {
        /// <summary>
        /// 根据图像控件，还原控件坐标为像素坐标
        /// </summary>
        /// <param name="points"></param>
        /// <param name="pictureBox"></param>
        /// <returns></returns>
        public static List<Point> ScalePoint(List<Point> points, PictureBox pictureBox)
        {
            float xbl = (float)pictureBox.Image.Width / (float)pictureBox.Width;
            float ybl = (float)pictureBox.Image.Height / (float)pictureBox.Height;

            var pts = new List<Point>();

            if (pictureBox.SizeMode == PictureBoxSizeMode.Zoom)
            {
                var bl = Math.Max(xbl, ybl);
                foreach (var p in points)
                {
                    pts.Add(new Point((int)(bl * p.X), (int)(bl * p.Y)));
                }

                var ofs = 0f;
                if (xbl > ybl)
                {
                    ofs = bl * pictureBox.Height - pictureBox.Image.Height;
                    for (int i = 0; i < pts.Count; i++)
                    {
                        var p = pts[i];
                        p.Y -= (int)(ofs / 2 - 1);
                        pts[i] = p;
                    }
                }
                else
                {
                    ofs = bl * pictureBox.Width - pictureBox.Image.Width;
                    for (int i = 0; i < pts.Count; i++)
                    {
                        var p = pts[i];
                        p.X -= (int)(ofs / 2 - 1);
                        pts[i] = p;
                    }
                }
            }
            else
            {
                foreach (var p in points)
                {
                    pts.Add(new Point((int)(xbl * p.X), (int)(ybl * p.Y)));
                }
            }

            return pts;
        }
        /// <summary>
        /// 前两点变成矩形
        /// </summary>
        /// <param name="pts"></param>
        /// <returns></returns>
        public static Rectangle ConvertToRect(List<Point> pts, bool allpt = false)
        {
            if (pts.Count > 1)
            {
                var rec = Drawing.CreateRectangle(pts[0], pts[1]);
                if (allpt)
                {
                    for (int i = 1; i < pts.Count; i++)
                        rec = Rectangle.Union(rec, Drawing.CreateRectangle(pts[i], pts[i - 1]));
                }
                return rec;
            }
            else
            {
                return new Rectangle(pts[0].X, pts[0].Y, 0, 0);
            }
      
        }
        /// <summary>
        /// 符号绘图 到指定图像
        /// </summary>
        /// <param name="defect"></param>
        /// <param name="g"></param>
        /// <param name="pts"></param>
        public static void DrawSymbol(DefectCatalog defect, Graphics g, List<Point> pts)
        {


            Pen pen = new Pen(defect.ColorOfPorL, (int)defect.LineWidth + 1);
            var bus = new HatchBrush(Common.ConvHstyle(defect.HatchPattern), defect.HatchColor, Color.Transparent);

            switch (defect.GeometryType)
            {
                case Gtype.点://point
                    var ps = ((int)defect.PointSize) * 5 + 3;
                    bus = new HatchBrush(HatchStyle.Percent75, defect.HatchColor, Color.Transparent);
                    foreach (var pt in pts)
                    {
                        Rectangle r = new Rectangle(pt.X, pt.Y, 0, 0);
                        r.Inflate(ps / 2, ps / 2);
                        g.DrawEllipse(pen, r);
                        g.FillEllipse(bus, r);

                        //
                    }
                    break;
                case Gtype.线://pline

                    if (defect.LineType == Ltype.虚线)
                    {
                        pen.DashStyle = DashStyle.Dash;
                        pen.DashPattern = new float[] { 4, 2 };
                        pen.DashOffset = 1;
                    }
                    if (pts.Count > 1)
                        g.DrawLines(pen, pts.ToArray());

                    break;
                case Gtype.面://polygon
                    if (pts.Count > 1)
                    {
                        g.DrawPolygon(pen, pts.ToArray());
                        g.FillPolygon(bus, pts.ToArray());
                    }

                    break;
                case Gtype.矩形:
                    if (pts.Count > 1)
                    {
                        g.DrawRectangle(pen, ConvertToRect(pts));
                        g.FillRectangle(bus, ConvertToRect(pts));
                    }
                    break;
                case Gtype.方向线:

                    g.DrawLines(pen, pts.ToArray());
                    // 计算线的角度
                    float angle = (float)Drawing.CalcAngle(pts[pts.Count - 1], pts[pts.Count - 2]);

                    // 创建EndCap的路径
                    GraphicsPath endCapPath = new GraphicsPath();
                    var size = ((int)defect.PointSize) * 5 + 20;
                    var po = Drawing.CalcAzRangePoint(pts[pts.Count - 1], size, angle + 180);
                    var px = Drawing.CalcAzRangePoint(po, size / 2, angle - 90);
                    // var p2 = Drawing.CalcAzRangePoint(pts[pts.Count - 1], size1 / 2, angle1 - 90);
                    //var p3 = Drawing.CalcAzRangePoint(pts[pts.Count - 1], size1, angle1);
                    endCapPath.AddLine(pts[pts.Count - 1], px);
                    // 绘制自定义的EndCap
                    g.DrawPath(pen, endCapPath);



                    break;
                case Gtype.箭头:
                    g.DrawLines(pen, pts.ToArray());
                    // 计算线的角度
                    float angle1 = (float)Drawing.CalcAngle(pts[pts.Count - 1], pts[pts.Count - 2]);

                    // 创建EndCap的路径
                    GraphicsPath endCapPath1 = new GraphicsPath();
                    var size1 = ((int)defect.PointSize) * 5 + 10;
                    var p0 = Drawing.CalcAzRangePoint(pts[pts.Count - 1], size1, angle1 + 180);
                    var p1 = Drawing.CalcAzRangePoint(p0, size1 / 2, angle1 + 90);
                    var p2 = Drawing.CalcAzRangePoint(p0, size1 / 2, angle1 - 90);
                    //var p3 = Drawing.CalcAzRangePoint(pts[pts.Count - 1], size1 , angle1);
                    //endCapPath1.AddLine(p2, p1);
                    //endCapPath1.AddLine(p2, pts[pts.Count - 1]);
                    //endCapPath1.AddLine(pts[pts.Count - 1], p1);
                    endCapPath1.AddPolygon(new PointF[] { p1, p2, pts[pts.Count - 1] });

                    // 绘制自定义的EndCap
                    g.DrawPath(pen, endCapPath1);
                    g.FillPath(bus, endCapPath1);
                    break;
                default:
                    break;
            }

        }
        /// <summary>
        /// 符号绘图到指定图像上
        /// </summary>
        /// <param name="defect"></param>
        /// <param name="bmp"></param>
        /// <param name="pts"></param>
        /// <returns></returns>
        public static Bitmap DrawSymbol(DefectCatalog defect, Bitmap bmp, List<Point> pts)
        {
            Graphics g = Graphics.FromImage(bmp);
            DrawSymbol(defect, g, pts);
            g.Dispose();
            return bmp;
        }

        /// <summary>
        /// 符号绘图
        /// </summary>
        /// <param name="defect"></param>
        /// <returns></returns>
        public static Bitmap DrawSymbol(DefectCatalog defect)
        {
            Bitmap bmp = new Bitmap(200, 200, System.Drawing.Imaging.PixelFormat.Format32bppRgb);
            var pts = new List<Point>();
            pts.Add(new Point(50, 50));
            pts.Add(new Point(120, 80));
            pts.Add(new Point(80, 130));
            var img = DrawSymbol(defect, bmp, pts);

            LabImg(img, "标注", defect.LabelingTextColor, new Point(50, 100), 0, defect.LabelFontSize == 0 ? 16 : defect.LabelFontSize);
            return img;

        }
        /// <summary>
        /// 填弃样式
        /// </summary>
        /// <param name="hpattern"></param>
        /// <returns></returns>
        public static HatchStyle ConvHstyle(Hpattern hpattern)
        {
            switch (hpattern)
            {
                case Hpattern.竖线:
                    return HatchStyle.Vertical;
                case Hpattern.斜线:
                    return HatchStyle.ForwardDiagonal;//
                case Hpattern.横线:
                    return HatchStyle.Horizontal;
                case Hpattern.点:
                    return HatchStyle.Percent05;
                case Hpattern.方格:
                    return HatchStyle.Cross;
                case Hpattern.填充:
                    return HatchStyle.Percent75;
                default:
                    return HatchStyle.Vertical;


            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="pts"></param>
        /// <returns></returns>
        /// <remarks>使用罗德里格斯公式（Shoelace formula）来快速计算多边形的面积。这个公式是通过将多边形的顶点坐标相乘并相互之间进行求和来计算的。公式如下：
        ///面积 A = 1 / 2 * ∑(xi* yi+1 - xi+1 * yi)
///其中，xi 和 yi 是多边形的顶点坐标</remarks>
        public static float GetArea(List<Point> pts)
        {
            double area = 0;
            for (int i = 0; i < pts.Count - 1; i++)
            {
                area += pts[i].X * pts[i + 1].Y - pts[i + 1].X * pts[i].Y;
            }
            area += pts[pts.Count - 1].X * pts[0].Y - pts[0].X * pts[pts.Count - 1].Y;

            return (float)Math.Abs(area / 2);

        }
        /// <summary>
         /// 获取前两点的距离
         /// </summary>
         /// <param name="pts"></param>
         /// <returns></returns>
        public static float GetDist(List<Point> pts)
        {
            return (float)Drawing.CalcDistance(pts[0], pts[1]);
        }
        /// <summary>
        /// 两点计算距离
        /// </summary>
        /// <param name="pt1"></param>
        /// <param name="pt2"></param>
        /// <returns></returns>
        public static float GetDist(Point pt1, Point pt2)
        {
            return (float)Drawing.CalcDistance(pt1, pt2);
        }
        /// <summary>
        /// 计算线段长度
        /// </summary>
        /// <param name="pts"></param>
        /// <returns></returns>
        public static float GetLenght(List<Point> pts)
        {
            var sum = 0f;
            for (int i = 1; i < pts.Count; i++)
            {
                sum += (float)Drawing.CalcDistance(pts[i], pts[i - 1]);
            }
            return sum;

        }
        /// <summary>
        /// 计算外接矩形中心点
        /// </summary>
        /// <param name="pts"></param>
        /// <returns></returns>
        public static PointF GetCenter(List<Point> pts)
        {
            if (pts.Count == 1) return pts[0];
            var rec = ConvertToRect(pts, true);
            return Drawing.Center(rec);

        }
        /// <summary>
        /// 最大宽度
        /// </summary>
        /// <param name="pts"></param>
        /// <returns></returns>
        public static float GetWidth(List<Point> pts)
        {
            return pts.Max(p => p.X) - pts.Min(p => p.X);
        }
        /// <summary>
        /// 最大高度
        /// </summary>
        /// <param name="pts"></param>
        /// <returns></returns>
        public static float GetHeight(List<Point> pts)
        {
            return pts.Max(p => p.Y) - pts.Min(p => p.Y);
        }

        /// <summary>
        /// 计算点集中到指定点的最小距离
        /// </summary>
        /// <param name="pts"></param>
        /// <param name="pt"></param>
        /// <returns></returns>
        public static float GetMinDist(List<Point> pts, Point pt)
        {
            return pts.Min(p => GetDist(p, pt));

        }
        /// <summary>
        /// 计算点集到点最大距离
        /// </summary>
        /// <param name="pts"></param>
        /// <param name="pt"></param>
        /// <returns></returns>
        public static float GetMaxDist(List<Point> pts, Point pt)
        {
            return pts.Max(p => GetDist(p, pt));
        }
        /// <summary>
        /// 点到直接距离
        /// </summary>
        /// <param name="pts"></param>
        /// <param name="pt"></param>
        /// <returns></returns>
        public static float GetDistToLine(List<Point> pts, Point pt)
        {
            double A = pts[1].Y - pts[0].Y;
            double B = pts[0].X - pts[1].X;
            double C = pts[1].X * pts[0].Y - pts[0].X * pts[1].Y;

            double dis = Math.Abs((A * pt.X + B * pt.Y + C) / Math.Sqrt(A * A + B * B));
            return (float)dis;
        }
        /// <summary>
        /// 点保到直线最短距离
        /// </summary>
        /// <param name="pts1">直线点集</param>
        /// <param name="pts"></param>
        /// <returns></returns>
        public static float GetMinDist(List<Point> pts1, List<Point> pts)
        {
            return pts.Min(p => GetDistToLine(pts1, p));
        }

        internal static void LabImg(Bitmap image, string str, Color color, PointF pt, float angleD, int fsize = 16)
        {
            if (fsize == 0) fsize = 16;
            Font font = new Font(SystemFonts.DefaultFont.FontFamily, fsize);

            Graphics g = Graphics.FromImage(image);

            g.DrawRotateString(str, font, color, pt, (float)(angleD));
            g.Dispose();
        }

        /// <summary>
        /// 标注缺陷信息
        /// </summary>
        /// <param name="oservations">缺陷信息</param>
        /// <param name="image">图像</param>
        /// <exception cref="NotImplementedException"></exception>
        internal static void LabImg(DefectOservations oservations, DefectCatalog defect, Bitmap image)
        {


            var p = GetCenter(oservations.Geometry);
            var rec = ConvertToRect(oservations.Geometry, true);
            var s = "";
            PointF pp; 
            if (defect.GeometryType != Gtype.方向线 && defect.GeometryType != Gtype.箭头)
            {
                if (defect.GeometryType == Gtype.点)
                {
                    p = p + new Size(0, 30);
                    LabImg(image, $"{oservations.Start:f2}m处\r\n{oservations.DefectCatalogName}{oservations.Grade}级", defect.LabelingTextColor, p, 0, defect.LabelFontSize);
                }
                else
                {
                    pp = new PointF(rec.Right + 70, p.Y);
                    if (defect.GeometryType == Gtype.面)
                    {

                        s = $"{oservations.Start:f2}m处\r\n" +
                                $"{oservations.DefectCatalogName}\r\n" +
                                $"W≈{oservations.Width:f1}m\r\n" +
                                $"L≈{oservations.Length:f1}m\r\n" +
                                $"S≈{oservations.Area:f2}㎡\r\n"+
                                $"{oservations.Score}分\r\n" +
                                $"{oservations.Grade}级";

                    }
                    else if (defect.GeometryType == Gtype.线)
                    {
                        s = $"{oservations.Start:f2}m处\r\n" +
                      $"{oservations.DefectCatalogName}\r\n" +
                      $"W≈{oservations.Width:f1}m\r\n" +
                      $"L≈{oservations.Length:f1}m\r\n" +
                      $"{oservations.Score}分\r\n" +
                      $"{oservations.Grade}级";
                    }
                    LabImg(image, s, defect.LabelingTextColor, pp, 0, defect.LabelFontSize);

                    // LabImg(image, $"{oservations.Start:f2}m处\r\n{oservations.DefectCatalogName}{oservations.Grade}级", defect.LabelingTextColor, pp, 0,defect.LabelFontSize);


                }


                #region 画面的井字线

                if (defect.GeometryType== Gtype.面 )
                {
                //    //画井字线
                //    Pen pen = new Pen(defect.LabelingTextColor, 1);
                //    Graphics g = Graphics.FromImage(image);
                //    var of = 10;
                //    var rec = ConvertToRect(oservations.Geometry, true);

                //    g.DrawLine(pen, rec.X - of, rec.Y, rec.X + rec.Width + of, rec.Y);//top -

                //    g.DrawLine(pen, rec.X - of, rec.Y+rec.Height, rec.X + rec.Width + of, rec.Y + rec.Height);//bom -

                //    g.DrawLine(pen, rec.X , rec.Y -of, rec.X , rec.Y + rec.Height+of);//left 1

                //    g.DrawLine(pen, rec.X+rec.Width, rec.Y - of, rec.X + rec.Width, rec.Y + rec.Height + of);//right 1

                //    g.Dispose();

                    //标注 长和宽

                    //pp=new PointF(p.X,rec.Y-20);
                    //LabImg(image, $"W≈{oservations.Width:f1}m", defect.LabelingTextColor, pp, 0, defect.LabelFontSize);
                    //pp = new PointF(rec.Right, rec.Y - 20);
                    //LabImg(image, $"L≈{oservations.Length:f1}m", defect.LabelingTextColor, pp, 0, defect.LabelFontSize);
                }
                #endregion



            }

        }
    }
}
